package cn.cimoc.service.impl;

import cn.cimoc.config.security.MyPasswordEncoder;
import cn.cimoc.constant.ConstantPool;
import cn.cimoc.constant.ErrorEnum;
import cn.cimoc.exception.CommonException;
import cn.cimoc.mapper.TUserRoleMapper;
import cn.cimoc.mapper.UserMapper;
import cn.cimoc.model.dto.inut.UserLoginInput;
import cn.cimoc.model.dto.output.UserInfo;
import cn.cimoc.model.po.TUser;
import cn.cimoc.model.po.TUserRole;
import cn.cimoc.service.UserService;
import cn.cimoc.util.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletResponse;

/**
 * @author LGZ
 * @date 2021/11/11 14:05
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Value("${role.defaultRid}")
    private long defaultRid;

    @Value("${role.defaultRole}")
    private String defaultRole;

    @Value("${token.validPeriod}")
    private long days;

    @Value("${img.type}")
    private String type;

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    UserMapper userMapper;

    @Autowired
    TUserRoleMapper tUserRoleMapper;

    @Autowired
    MyPasswordEncoder passwordEncoder;

    private static final DateTimeFormatter PATTERN = DateTimeFormatter.ofPattern("yyyyMMdd");

    /**
     * 不同系统的磁盘分隔分
     */
    private final String separator = File.separator;

    @Value("${img.path}")
    private String imgPath;

    @Value("${img.handler}")
    private String handler;

    @Override
    public void register(String username, String password, HttpServletResponse response) {

        QueryWrapper<TUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        TUser res = userMapper.selectOne(wrapper);
        if (null != res) {
            HttpStatus.mistake(ErrorEnum.USERNAME_ALREADY_EXISTS);
        }

        TUser user = new TUser();
        user.setUsername(username);
        user.setPassword(passwordEncoder.encode(password));

        // 生成新的token
        Map<String, String> map = new HashMap<>();
        map.put(ConstantPool.USERNAME, username);
        map.put(ConstantPool.ROLE, ConstantPool.ROLE_PREFIX + defaultRole);
        String token = JwtUtils.getToken(map);
        redisUtils.set(token, "", TimeUnit.DAYS.toSeconds(days));

        userMapper.insert(user);
        redisUtils.hSet(ConstantPool.USER_PREFIX + user.getUsername(), ConstantPool.USER_ID, user.getUid());
        response.setHeader(JwtUtils.TOKEN_HEADER, JwtUtils.TOKEN_PREFIX + token);

        TUserRole tUserRole = new TUserRole();
        tUserRole.setUid(user.getUid());
        tUserRole.setCreatedUser(username);
        tUserRole.setRid(defaultRid);
        tUserRoleMapper.insert(tUserRole);
    }

    @Override
    public void changePassword(String op, String np, Long uid) {
        TUser tUser = userMapper.selectById(uid);

        if (!tUser.getPassword().equals(MD5Utils.encode(op))) {
            HttpStatus.mistake(ErrorEnum.WRONG_PASSWORD);
        }

        tUser.setPassword(MD5Utils.encode(np));
        userMapper.updateById(tUser);
    }

    @Override
    public UserInfo getInfo(Long uid) {
        TUser tUser = userMapper.selectById(uid);
        return CommonUtils.getMapperFacade().map(tUser, UserInfo.class);
    }

    @Override
    public void changeInfo(String phone, String email, long gender, long uid) {
        UpdateWrapper<TUser> wrapper = new UpdateWrapper<>();
        wrapper.set("phone", phone);
        wrapper.set("email", email);
        wrapper.set("gender", gender);
        wrapper.eq("uid", uid);
        userMapper.update(null, wrapper);
    }

    @Override
    public String changeAvatar(MultipartFile img, long uid) {
        String uploadFileName = img.getOriginalFilename();
        if (!StringUtils.hasLength(uploadFileName)) {
            HttpStatus.mistake(ErrorEnum.FILE_UPLOAD_FAILED_OF_NAME_ILLEGAL);
        }
        // 重命名文件，防止实际存储的文件名重复，文件原名保存到数据库
        String uuid = CommonUtils.generateUUID();
        String suffixName = uploadFileName.substring(uploadFileName.lastIndexOf("."));

        if (!type.contains(suffixName.substring(1))) {
            HttpStatus.mistake(ErrorEnum.IMG_FILE_TYPE_ERROR);
        }

        String newName = uuid + suffixName;

        // 每一天的文件都新建一个文件夹，以日期命名
        String date = LocalDateTime.now().format(PATTERN);
        String path = imgPath + separator + date;

        //如果路径不存在，创建一个
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdirs();
        }
        try{
            //文件输入流
            InputStream is = img.getInputStream();
            //文件输出流
            OutputStream os = new FileOutputStream(new File(realPath, newName));
            //读取写出
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
                os.flush();
            }
            os.close();
            is.close();
            UpdateWrapper<TUser> wrapper = new UpdateWrapper<>();
            wrapper.eq("uid", uid);
            wrapper.set("avatar", handler + separator + date + separator + newName);
            userMapper.update(null, wrapper);
        }catch (Exception e){
            log.error("错误信息:[{}]",e.getMessage());
            HttpStatus.mistake(ErrorEnum.FILE_UPLOAD_FAILED_WITH_UNKNOWN_EXCEPTION);
        }
        return handler + separator + date + separator + newName;
    }
}
